package com.nulldev.util.web.HttpServer3;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import com.nulldev.util.data.Variables;
import com.nulldev.util.data.Sets.DataTriplet;
import com.nulldev.util.io.IOUtils;
import com.nulldev.util.io.file.FileUtil;
import com.nulldev.util.io.legacy.MimeType;
import com.nulldev.util.web.HttpServer3.MicroCache.CachedPage;
import com.nulldev.util.web.HttpServer3.legacyPages.v1.HttpPage;
import com.nulldev.util.web.HttpServer3.legacyPages.v1.RequestType;
import com.nulldev.util.web.HttpServer3.legacyPages.v2.HttpPage2;
import com.nulldev.util.web.HttpServer3.pages.v3.HttpPage3;
import com.nulldev.util.web.HttpServer3.pages.v3.HttpPage3.CachingMethod;
import com.nulldev.util.web.HttpServer3.pages.v3.HttpPage3.EnhancedSecurityChecks;

public interface HttpServer {
	public boolean addPage(final Page page);

	public Page getPage(final String id, final Object sock);

	public HttpServer3Flags flags();

	public HttpServer3Settings settings();

	public void addDynamicAssetBytes(final String name, final Class<?> reference, final String assetName, final CachingMethod cache,
			final boolean captchaExclusion);

	@SuppressWarnings("resource")
	public static Response do_response(final HttpServer server, final RequestType type, final String[] request, final ReadRequest rr,
			/* final byte[] extraData , */ final Socket socket, final Map<String, String> headers, final Page page) throws IOException {
		if (page instanceof HttpPage3) {
			return ((HttpPage3) page).onRequest(
					new HttpPage3.Request(request[1], rr.hasStream() ? rr.stream() : HttpPage3.BLANK_IO_STREAM, socket.getInetAddress().getHostAddress())
							.importHeaders(headers).setRequestType(type));
		} else if (page instanceof HttpPage2) {
			final byte[] extraData = rr.hasStream() ? IOUtils.toByteArray(rr.stream()) : null;
			return new Response(((HttpPage2) page).request(type, request[1], rr.headers_legacy(), extraData, socket.getInetAddress().getHostAddress()));
		} else if (page instanceof HttpPage) {
			final HttpPage p = ((HttpPage) page);
			if (p.isOverBytes()) {
				return new Response(new DataTriplet<Integer, InputStream, Map<String, String>>(200,
						new ByteArrayInputStream(p.handleRequest_Alt(request[1], socket.getInetAddress().getHostAddress(), type)),
						new TreeMap<String, String>()));
			} else if (p.sendRaw()) {
				return new Response(
						new DataTriplet<Integer, InputStream, Map<String, String>>(200, new FileInputStream(p.getPath()), new TreeMap<String, String>()));
			} else {
				return new Response(new DataTriplet<Integer, InputStream, Map<String, String>>(200,
						new ByteArrayInputStream(p.handleRequest(request[1], socket.getInetAddress().getHostAddress(), type).getBytes()),
						new TreeMap<String, String>()));
			}
		} else if (page instanceof CachedPage) {
			final CachedPage cp = (CachedPage) page;
			return new Response(200, cp, cp);
		} else {
			return null;
		}
	}

	/* */

	public static void addFolder(final HttpServer server, final File file) {
		Variables.requireNonNull(server, "server");
		Variables.requireNonNull(file, "file");
		if (!file.isDirectory())
			throw new RuntimeException("Invalid folder: location is not a folder!");
		final List<File> files = FileUtil.listFilesForFolder(file);
		final String oPath = file.getPath();
		files.forEach((_file) -> {
			if (_file.isDirectory())
				return;
			final String fPath = _file.getPath();
			final String truePath = fPath.replace(oPath, "").substring(1);
			final MimeType mt = MimeType.fromFileString(_file.getName());
			if (!server.addPage(new HttpPage3(truePath) {

				@Override
				public Response onRequest(final Request request) {
					Response r;
					try {
						r = new Response(200, createStream(FileUtil.readFileToBytes(_file)));
					} catch (Exception e) {
						r = new Response(503);
					}
					if (mt != MimeType.UNKNOWN)
						r.setCustomMime(mt.getType());
					return r;
				}
			}.setCachingMethod(CachingMethod.SHORT_CACHE).setChecks(EnhancedSecurityChecks.DISALLOW_POST_DATA,
					EnhancedSecurityChecks.ONLY_ALLOW_BASIC_METHODS))) {
			}
		});
	}

}
